Alrighty, in this lecture, we're going to be creating a leaderboard that is going to keep track of
the stages and deaths for all players in a server.
Tracking deaths is going to be easy, but since the Abi is generated on the client, we'll have to use
our remote event to let the server know when we have touched a new checkpoint, and then the server
will have to do some sanity checks to make sure that the remote event isn't being fired too fast.
Now we can let the server know when we've touched new checkpoint by going to our RB generation handler.
And when we go, when we touch a new checkpoint, what we could do is we could fire that remote event
to let the server know that we would like to increment our stage to the next stage that we are at.
So we can go ahead and get this event.
And I'm just going to call it leader board Comms event.
And this event is located in Replicated storage and the events folder and it's called Leaderboard comms.
And then we can use this event to fire to the server to do a specific action.
Now a way for us to keep track of all of the actions that we can have the server perform.
What we could do is we could go into replicated storage, and in our modules folder we can create a
new module script underneath the enums folder.
And this module script in here is going to act as a custom enum.
So we can call this our leaderboard comms enum.
And inside of here we can just call a table self.
And we'll make sure to return self at the end of this module.
And inside of this table is where we're going to store basically the enums for different actions.
Now I can specify which actions belong to the server or to the client.
And I'll create a key in here called to server.
And we'll store a table.
And inside of this table is where we can store all of our different actions.
So for example when I touch a new checkpoint I want to tell the server to increment what stage I'm at
so I can call this action increment stage and just set it equal to a string that says increment stage.
So this is like my pseudo enum basically.
And then I can go ahead and require this enum.
I'll call it leaderboard comms enum and we'll require from replicated storage, dot modules, dot enums,
dot leaderboard comms enum.
And that way when we touch a checkpoint model, we can go ahead and use the leaderboard comms event
and fire to the server and give it the action of our leaderboard comms enum dot two server dot increment
stage.
And since we're returning once the checkpoint model is set to whatever model was touched, that means
we're only going to fire this event once per stage.
Now to set up the leaderboard on the server.
What we can do is open up server script service and add a new service in here, or a new module script.
And I'm going to call this my leaderboard service.
And I'm going to use that template we've been using previously, and I'm going to rename it to Leader
Board Service.
And inside of here, we're going to need the player service.
As well as replicated storage.
And then we can go ahead and refer to that same event, which is our leaderboard.
Com's event and replicated storage dot events, dot leaderboard coms.
And then we'll get the exact same enum.
So leader board comms enum require replicated storage dot modules dot enums dot leaderboard comms enum.
And to make sure that the players don't fire this event too quickly, we can go ahead and create a table.
I'll call it player time stamps.
And this will keep track of whenever the player last fired this event.
And if they're firing it too quickly, then we can basically mark up some warnings for this player.
And then once their warnings exceeds a certain threshold, then we can kick the player out of the game
because they might be cheating.
So we'll create another table.
I'll call it player warn counts, and that's where we'll store warnings for each player.
And then we can go ahead and define those thresholds.
Here I'll call this, um, my warn count threshold.
So once they get above let's say five warnings, then we'll kick them from the game.
And then we also want to define a constant that's going to be the threshold for the time duration between
events being fired.
So I'll call it event uh threshold.
And I'll set it to something like one second.
So if the client is firing this event faster than one second, that means they might be cheating and
firing this remote event, or they might be flying through the map or whatever.
We want to set a warning for them.
Now.
The service, of course, needs to set up a leaderboard for every single player in our game.
So we'll create a function for doing that.
We'll call it Setup Leader stats for and we'll pass a player to this function.
And also have a function to listen for when a player's character dies.
So we'll call it on character death, and we'll pass a player instance to this to get.
Which player's character died, and then from there we would increment the death value in their leader
stats.
So in this initialized section, what we want to do is we want to listen to the players that player
added event and connect a function to this and get that player.
We can go ahead and set up the lidar stats for that player.
And then we would also want to listen for when a character is added to this player.
Look at that character, and then we want to listen for when that character dies.
So we'll refer to the character humanoid died event connect a function.
And this is where we would call our on character death.
And this is where we would call our on character death and pass the player.
And then we also want to loop through every single player in the game, get players.
And we're basically just going to do the exact same thing, set up the leader stats for this player,
and then just basically copy that, paste that in there and we should be good to go.
One last thing we can go ahead and check for when we're testing in studio is that this might execute
after the player already had a character added to them, so we can add an if statement to quickly check
if they already have a character.
So I'll just copy this here.
And then change this to player character.
And then afterwards we want to go ahead and connect to that remote event that's in replicated storage.
So leaderboard comms event we want to listen to on server event connect a function to this.
And we're going to be given the player that fired this event as well as the action they would like us
to do.
And we can go ahead and check if this action is equal to our leaderboard.
Comms enum dot two server dot increment stage.
If it is, then this is where we're going to want to check, um the timestamp for this player.
Now when this event gets fired, we want to make sure we go ahead and add a key to our timestamp table.
So if this player does not have a timestamp in our player timestamps table, we'll use their name as
the key.
Then we'll go ahead and set it up for them.
We'll do player timestamps player dot name.
We'll set it equal to the current tech and subtract that by our event threshold.
So that way we don't accidentally flag them when we first set up this table for them.
And then if the action they have us do is going to be incrementing their stage, then we'll check the
current tick and subtract it by whenever they fired this event last.
So we'll just copy this.
And if them firing this event is faster than the event threshold.
So if it's less than the event threshold, then what we want to do is we want to check if they have
a key inside of the player.
One counts.
If they don't, we need to set it up.
So if not player one counts, pass their name, then we'll go ahead and set it up for them.
So we'll copy this and set it equal to one.
Otherwise, we'll go ahead and copy this and then increment the value that's already there by one.
And then if they're player one counts for this particular player exceeds the threshold we set.
So if this becomes greater than our one count threshold then we need to kick the player.
So player kick we'll just say unusual client behavior detected.
Otherwise we could give a warning in the console.
We could say something like, uh, user.
We'll say player name.
Fired the remote event.
Uh, I will just say leader board comms.
Eventname.
They fired this remote event two fast.
Otherwise, we can go ahead and set player timestamps for this player equal to the current tick.
And then we would update the value in their leader stats.
So let's go ahead and set up the leader stat function.
Inside of here we'll create a new folder for our leader stats.
So instance dot new folder.
Leaderstats dot name equal to Leaderstats Leaderstats dot parent equal to our player.
And then we'll go ahead and create some int values.
I'll call this one stage instance dot new int value.
Stage name is going to be equal to stage.
And then stage that value is going to be zero.
And then stage dot parent is going to be equal to liter stats.
And then we can just copy this and do the exact same thing.
But instead we're going to do it for our deaths.
So we'll rename this to deaths.
Change the name here to deaths.
And there we go.
We'll set up a liter stat for that player.
And then when their player dies we'll refer to this players liter stats folder, get their deaths in
value and set the value plus equal to one.
And then we do the same thing down here.
We're going to refer to the player dot liter stats.
Get their stage.
Set the value plus equal to one.
And we're not going to need a start function for the service, so we'll get rid of that.
And the one last thing I'm going to add is I'm going to listen to the players player removing event,
connect a function and get that player.
That's because we want to go ahead and clear up any memory.
If this player is stored in the player's timestamps table, or if they're played in the player worn
count table.
So we'll set player timestamps for this particular player equal to nil, as well as for the player worn
counts.
We'll get that player and set that equal to nil.
And I think we've got everything set up for our leaderboard.
So now any time our player dies, we're going to increment their leader stats.
And then any time the player fires that event to us we're going to increment their stage.
So let's go ahead and try it out.
If we go and play test the game here there's our leader stats.
If we touch the first stage there we are.
We're on stage one I got blown up by a landmine.
So there's a hidden trap right there.
Let me make sure not to touch those stuff.
And we're currently incrementing stages are going up and it also incremented our death there.
So that's cool.
And we'll just keep walking along.
Oh there's a shotgun trap.
So and there's another landmine.
But deaths are working.
Stage increment is working.
If I go and die again.
There we go.
Deaths get incremented.
Very cool.
We are nearly done with this project.
The last thing we're going to add is a day time cycle, and we'll do that in the next lecture.
See you there.